﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ModelingProjectLib.Interfaces;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows;

namespace INSAwarsWPF
{
    /** ViewModel qui encapsule une Ville */
    public class VilleViewModel : ViewModelBase
    {
        /** Modèle de ville encapsulé */
        public Ville VilleModel { get; set; }

        /** Cases sous influence de la ville */
        public HashSet<CaseViewModel> CasesInfluencees { get; set; }

        /** Case dans laquelle est contenue la ville */
        public CaseViewModel Conteneur { get; private set; }

        /** Construit un nouveau VilleViewModel pour la ville _ville sur la case _cvm */
        public VilleViewModel(CaseViewModel _cvm, Ville _ville)
        {
            CasesInfluencees = new HashSet<CaseViewModel>();
            Conteneur = _cvm;
            VilleModel = _ville;
        }
        /*
        public string ResumeVie
        { get { return "(" + VilleModel.Vie + "/" + VilleModel.VieMax + ")"; } }
        */
        /** Renvoie la texture de la ville */
        public string Texture
        {
            get { return "/INSAwarsWPF;component/Images/Villes/ville_36.png"; }
        }

        /** Renvoie un résumé de la vie de la ville */
        public string ResumeVie { get { return "(" + VilleModel.Vie + "/" + VilleModel.VieMax + ")"; } }

        /** Renvoie le contenu du bouton de création de ville, fonction du prochain seuil de nourriture */
        public string DescriptionCout { get { return "Étendre la ville (" + VilleModel.ProchainSeuilNourriture + " No)"; } }

        /** Tableau des couleurs utilisées pour les joueurs */
        public string Couleur { get { return CaseViewModel.tabCouleur[VilleModel.Possesseur.Num - 1]; } }
        /** Tableau des couleurs réelles utilisées pour les joueurs */
        public string CouleurCode { get { return CaseViewModel.tabCouleurCode[VilleModel.Possesseur.Num - 1]; } }

        /** Vrai ssi la ville appartient au joueur courant */
        public bool IsPossedeeParJoueurCourant
        { get { return Conteneur.Conteneur.PartieCourante.JoueurCourant == VilleModel.Possesseur; } }
        /** Vrai ssi la ville n'appartient pas au joueur courant */
        public bool IsNotPossedeeParJoueurCourant
        { get { return Conteneur.Conteneur.PartieCourante.JoueurCourant != VilleModel.Possesseur; } }

        /** Vrai ssi la ville a déjà créé une unité à ce tour */
        public bool ADejaCree { get; set; }

        /** Vrai ssi la ville peut s'étendre */
        public bool PeutSEtendre
        { get { return VilleModel.Nourriture >= VilleModel.ProchainSeuilNourriture; } }

        /** Vrai ssi la ville peut créer un directeur */
        public bool PeutCreerDirecteur
        { get { return !Conteneur.Pleine
            && !Conteneur.Conteneur.Joueurs.JoueurCourant.HasDirecteur
            && VilleModel.Minerai >= 200
            && !ADejaCree; } }

        /** Vrai ssi la ville peut créer un enseignant */
        public bool PeutCreerEnseignant
        { get { return !Conteneur.Pleine
            && VilleModel.Minerai >= 60
            && !ADejaCree;
        }
        }

        /** Vrai ssi la ville peut créer un étudiant */
        public bool PeutCreerEtudiant
        { get { return !Conteneur.Pleine
            && VilleModel.Minerai >= 100
            && !ADejaCree; }
        }

        /** Permet de marquer la case _case comme influencée par la ville */
        public void influencer(CaseViewModel _case)
        {
            CasesInfluencees.Add(_case);
            _case.VilleInfluente = this;
        }

        /** Supprime la ville après attaque par un attaquant */
        public void supprimer(UniteViewModel attaquant)
        {
            attaquant.VillesAttaqueesACeTour.Remove(this);
            supprimer();
        }

        /** Supprime la ville : sa zone d'influence, et la déréférence de sa case contenante, de son joueur.
         * Vérifie si le joueur n'est pas mort et si la partie n'est pas finie */
        public void supprimer()
        {
            // on nettoie la zone d'influence
            foreach (CaseViewModel caseInfl in CasesInfluencees)
            {
                caseInfl.VilleInfluente = null;
            }
            CasesInfluencees.Clear();

            Conteneur.Conteneur.Joueurs.getJoueurVMFromJoueur(VilleModel.Possesseur).Villes.Remove(this);
            // Conteneur.Conteneur.Joueurs.JoueurCourant.Villes.Remove(this); on supprime pas forcément la ville du joueur courant !

            Conteneur.VilleCase = null;
           // Conteneur.Conteneur.Joueurs.JoueurCourant.majJoueurApresDeplacementUnite();

            
            if (!Conteneur.Conteneur.Joueurs.joueurIsEnVie(VilleModel.Possesseur))
                Conteneur.Conteneur.Joueurs.supprimerJoueur(VilleModel.Possesseur);

            Conteneur = null;

            // mise à jour du modèle
            VilleModel.Possesseur.Civilisation.ListVilles.Remove(VilleModel);
            VilleModel = null;
        }

        /** Influence la zone de centre centre et de rayon 3 */
        public void influencerZone(CaseViewModel centre)
        {
            // on nettoie la liste dans le cas d'une remie à jour
           // CasesInfluencees.Clear();

            for (int i = -(VilleModel.Diametre / 2); i <= VilleModel.Diametre / 2; i++)
            {
                for (int j = -(VilleModel.Diametre / 2); j <= VilleModel.Diametre / 2; j++)
                {
                    if (centre.Column + i >= 0 && centre.Column + i < Conteneur.Conteneur.PartieCourante.CartePartie.Taille
                        && centre.Row + j >= 0 && centre.Row + j < Conteneur.Conteneur.PartieCourante.CartePartie.Taille)
                    {
                        int ind = (centre.Column + i) + Conteneur.Conteneur.PartieCourante.CartePartie.Taille * (centre.Row + j);
                        CaseViewModel caseInfl = Conteneur.Conteneur.Cases[ind];

                        if (!caseInfl.IsSousInfluenceDeVille)
                        {
                            CasesInfluencees.Add(caseInfl);
                            caseInfl.VilleInfluente = this;
                        }
                    }
                }
            }
        }

        /** Récolte au début de chaque tour les ressources présentes sur les cases influencées */
        public void recolterRessources()
        {
            foreach (CaseViewModel cvm in CasesInfluencees)
            {
                VilleModel.Minerai += cvm.CaseModel.getRessourceMinerai();
                VilleModel.Nourriture += cvm.CaseModel.getRessourceNourriture();
            }
        }

        /** Fonction qui essaye d'étendre la ville courante vers la case caseExtension
         * return true si l'extension est réussie
         * return false si la case n'était pas valide
         */
        public bool etendre(CaseViewModel caseExtension)
        {
            if (caseExtension.HasUniteEnnemie
                || caseExtension.HasVille
                || caseExtension.IsSousInfluenceDeVille
                || !checkExtensionPossible(caseExtension)) {
                MessageBox.Show("La case sélectionnée est invalide");
                return false;
            }
            
            VilleModel.Nourriture -= VilleModel.ProchainSeuilNourriture;
            VilleModel.ProchainSeuilNourriture += VilleModel.ProchainSeuilNourriture / 2;
            // VilleModel.Diametre += 2;
            VilleModel.Population++;
            influencer(caseExtension);

            //influencerZone(Conteneur);

            RaisePropertyChanged("PeutSEtendre");
            RaisePropertyChanged("DescriptionCout");

            return true;
        }

        /** Vérifie si l'extension est possible */
        private bool checkExtensionPossible(CaseViewModel caseExtension)
        {
            CaseViewModel adj = null;

            if ((adj = caseExtension.getCaseRelative(-1, 0)) != null && adj.VilleInfluente == this)
                return true;
            else if ((adj = caseExtension.getCaseRelative(1, 0)) != null && adj.VilleInfluente == this)
                return true;
            else if ((adj = caseExtension.getCaseRelative(0, -1)) != null && adj.VilleInfluente == this)
                return true;
            else if ((adj = caseExtension.getCaseRelative(0, 1)) != null && adj.VilleInfluente == this)
                return true;
            else
                return false;
        }

        /** Produit l'unité u : la crée sur la case de la ville */
        private void produireUnite(Unite u)
        {
            int ind = Conteneur.Column + Conteneur.Conteneur.PartieCourante.CartePartie.Taille * Conteneur.Row;

            UniteViewModel unitVM = new UniteViewModel(Conteneur.Conteneur.Cases[ind], u);
            Conteneur.Conteneur.Cases[ind].Unites.Add(unitVM);
            Conteneur.Conteneur.Joueurs.JoueurCourant.Unites.Add(unitVM);

            ADejaCree = true;

            RaisePropertyChanged("PeutCreerDirecteur");
            RaisePropertyChanged("PeutCreerEnseignant");
            RaisePropertyChanged("PeutCreerEtudiant");
        }

        /** Produit un directeur en consommant des ressources */
        public void produireDirecteur()
        {
            int row = Conteneur.Row;
            int col = Conteneur.Column;

            Directeur d = VilleModel.Possesseur.Civilisation.creerDirecteur(row, col);

            VilleModel.Minerai -= 200;

            produireUnite(d);
        }

        /** Produit un enseignant en consommant des ressources */
        public void produireEnseignant()
        {
            int row = Conteneur.Row;
            int col = Conteneur.Column;

            Enseignant e = VilleModel.Possesseur.Civilisation.creerEnseignant(row, col);

            VilleModel.Minerai -= 60;

            produireUnite(e);
        }

        /** Produit un étudiant en consommant des ressources */
        public void produireEtudiant()
        {
            int row = Conteneur.Row;
            int col = Conteneur.Column;

            Etudiant e = VilleModel.Possesseur.Civilisation.creerEtudiant(row, col);

            VilleModel.Minerai -= 100;

            produireUnite(e);
        }
    }
}
